package buco.core.api;

import java.io.IOException;
import java.util.*;

import buco.filemanagement.*;

/**
 * Represents an execution context for a single composition. 
 * This class maintains an instance of BundleComposition together with additional services. 
 * It is used to execute commands within this context. 
 * 
 * @author Christopher
 *
 */
public class CompositionContext {
	
	@SuppressWarnings("rawtypes")
	private Stack<Command> undoStack;
	private Stack<Command> redoStack;
	private BundleComposition composition;
	private FileManager fileManager;
	
	@SuppressWarnings("rawtypes")
	public CompositionContext(String baseDir) { 
		undoStack = new Stack<Command>(); 
		redoStack = new Stack<Command>();
		try {
			composition = new BundleComposition();
			fileManager = new FileManager(baseDir); 
		} catch (IOException e) {
			e.printStackTrace();
		} 		
	}
	
	@SuppressWarnings("rawtypes")
	public CompositionContext() { 
		this("fileman"); 
	}
	
	public <TIn, TOut> TOut execute(Command<TIn, TOut> command, TIn input) throws Exception {
		command.setFileManager(fileManager);
		command.setComposition(composition);
		
		// Only push commands that can be undone. 
		if(command.canUndo()) { 
			undoStack.push(command);
		}
		
		command.setParameters(input); 		
		return command.execute();
	}
	
	public BundleComposition getComposition() { 
		return this.composition; 
	}
	
	public void close() { 
		fileManager.deleteAll();
	}
	
	public FileManager getFileManager() { 
		return fileManager; 
	}
	
	public void undo() {
		if(!undoStack.empty()) {
			Command cmd = undoStack.pop();
			cmd.undo(); 
			redoStack.push(cmd);
		}
	}
	
	public void redo() {
		if(!redoStack.empty()) {
			Command cmd = redoStack.pop();
			try {
				cmd.execute();
			} catch (Exception e) {
				e.printStackTrace();
			} 
			undoStack.push(cmd);
		}
	}
	
	public boolean canUndo() {
		return !undoStack.empty(); 
	}
	
	public boolean canRedo() {
		return !redoStack.empty(); 
	}
	
	public void newComposition() {
		close();  
		composition = new BundleComposition(); 
		try {
			fileManager = new FileManager("fileman");
		} catch (IOException e) {		
			e.printStackTrace();
		}
	}
}
